package cn.silver.module.quartz.util;


import cn.silver.framework.core.exception.ServiceException;
import cn.silver.framework.core.utils.StringUtils;
import cn.silver.module.quartz.enums.QuartzStatusEnums;
import cn.silver.module.quartz.enums.QuartzStrategyEnums;
import cn.silver.module.quartz.domain.SysJob;
import org.quartz.*;

/**
 * 定时任务工具类
 *
 * @author Silver.Zhou
 */
public class ScheduleUtils {

    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";

    /**
     * 执行目标key
     */
    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
    /**
     * 得到quartz任务类
     *
     * @param job 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(SysJob job) {
        boolean isConcurrent = job.getConcurrent();
        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
    }

    /**
     * 构建任务触发对象
     */
    public static TriggerKey getTriggerKey(String jobId, String jobGroup) {
        return TriggerKey.triggerKey(TASK_CLASS_NAME + jobId, jobGroup);
    }

    /**
     * 构建任务键对象
     */
    public static JobKey getJobKey(String jobId, String jobGroup) {
        return JobKey.jobKey(TASK_CLASS_NAME + jobId, jobGroup);
    }

    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException {
        Class<? extends Job> jobClass = getQuartzJobClass(job);
        // 构建job信息
        String jobId = job.getId();
        String jobGroup = job.getGroup();
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();

        // 表达式调度构建器
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule(job.getExpression());
        builder = handleCronScheduleMisfirePolicy(job, builder);

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
                .withSchedule(builder).build();

        // 放入参数，运行时的方法可以获取
        jobDetail.getJobDataMap().put(TASK_PROPERTIES, job);

        // 判断是否存在
        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
            // 防止创建时存在数据问题 先移除，然后在执行创建操作
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        }

        scheduler.scheduleJob(jobDetail, trigger);

        // 暂停任务
        if (QuartzStatusEnums.QUARTZ_PAUSE.getCode().equalsIgnoreCase(job.getStatus())) {
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
    }

    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) {
        QuartzStrategyEnums strategy = QuartzStrategyEnums.getStrategy(job.getStrategy());
        return switch (strategy) {
            case STRATEGY_DEAFUAL -> cb;
            case STRATEGY_IMMEDIATE -> cb.withMisfireHandlingInstructionIgnoreMisfires();
            case STRATEGY_ONCE -> cb.withMisfireHandlingInstructionFireAndProceed();
            case STRATEGY_ABANDON -> cb.withMisfireHandlingInstructionDoNothing();
            default -> throw new ServiceException("任务配置异常");
        };
    }

    /**
     * 检查包名是否为白名单配置
     *
     * @param invokeTarget 目标字符串
     * @return 结果
     */
    public static boolean whiteList(String invokeTarget) {
        String packageName = StringUtils.substringBefore(invokeTarget, "(");
        int count = StringUtils.countMatches(packageName, ".");
//        if (count > 1) {
//            return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
//        }
        return true;
    }
}
